#include "File.h"
#include "../infLib/infLib.h"
#include <cstdio>

const int FILE_MAX_STRING = 65534;

int SEEK_MAP[3] = { SEEK_SET, SEEK_CUR, SEEK_END };

bool	        File::Eof( void ) {
	return Tell() >= Length();
}

void			File::Rewind( void ){
	Seek(0, FS_SEEK_END);
}

static char endianBuf[16] = {0};
static int size = 0;
using namespace inf;

int 			File::ReadInt( void ) {
	size = Read(endianBuf,sizeof(int));
	assert(size);

	return little_long(*(int*)endianBuf);
}
unsigned int	File::ReadUnsignedInt( void ) {
	size = Read(endianBuf,sizeof(unsigned int));
	assert(size);

	return static_cast<unsigned int>( little_long(*(int*)endianBuf) );
}
short			File::ReadShort( void ) {
	size = Read(endianBuf,sizeof(short));
	assert(size);

	return little_short(*(short*)endianBuf);
}
unsigned short	File::ReadUnsignedShort( void) {
	size = Read(endianBuf,sizeof(unsigned short));
	assert(size);

	return static_cast<unsigned short>( little_short(*(short*)endianBuf) );
}
char			File::ReadChar( void ){
	size = Read(endianBuf,sizeof(char));
	assert(size);

	return static_cast<char>( endianBuf[0] );
}
unsigned char	File::ReadUnsignedChar( void ){
	size = Read(endianBuf,sizeof(unsigned char));
	assert(size);

	return static_cast<unsigned char>( endianBuf[0] );
}
float   		File::ReadFloat( void ){
	size = Read(endianBuf,sizeof(float));
	assert(size);

	return little_float(*(float*)endianBuf);
}
bool			File::ReadBool( void ){
	size = Read(endianBuf,sizeof(bool));
	assert(size);

	return (endianBuf[0] == 1);
}

void			File::ReadString( inf::Str &string ){
	/*
	unsigned short: [string length]
	string data: ...
	string end: '\0'
	*/
	unsigned short length = ReadUnsignedShort();
	assert(length);

	char* stringData = new char[length+1];
	if( Read(stringData, length) == length ) {
		stringData[length] = '\0';
		string = stringData;
		delete [] stringData;
		return; // OK!
	}

	// failed!
	delete [] stringData;
}

void				File::ReadVec2( inf::Vec2 &vec ){
	ReadFloatArray(vec.to_float_ptr(), vec.get_dimension());
}
void				File::ReadVec3( inf::Vec3 &vec ){
	ReadFloatArray(vec.to_float_ptr(), vec.get_dimension());
}
void				File::ReadCQuat( inf::CQuat& quat ) {
	ReadFloatArray(quat.to_float_ptr(), quat.get_dimension());
}
void				File::ReadAngles( inf::Angles& angles ) {
	ReadFloatArray(angles.to_float_ptr(), angles.get_dimension());
}
void				File::ReadVec4( inf::Vec4 &vec ) {
	ReadFloatArray(vec.to_float_ptr(), vec.get_dimension());
}
void			File::ReadMat3( inf::Mat3 &mat ) {
	ReadFloatArray(mat.to_float_ptr(), mat.get_dimension());
}
void			File::ReadFloatArray( float* src, const int num )
{
	for(int i=0; i<num; ++i) {
		src[i] = ReadFloat();
	}
}

void			File::WriteInt( const int value ){
	*(int*)endianBuf = little_long(value);
	Write(endianBuf, sizeof(value));
}
void			File::WriteUnsignedInt( const unsigned int value ){
	*(unsigned int*)endianBuf = little_long((int)value);
	Write(endianBuf, sizeof(value));
}
void				File::WriteShort( const short value ){
	*(short*)endianBuf = little_short(value);
	Write(endianBuf, sizeof(value));
}
void				File::WriteUnsignedShort( unsigned short value ){
	*(unsigned short*)endianBuf = little_short((short)value);
	Write(endianBuf, sizeof(value));
}
void				File::WriteChar( const char value ){
	Write(&value, sizeof(value));
}
void				File::WriteUnsignedChar( const unsigned char value ){
	Write(&value, sizeof(value));
}
void				File::WriteFloat( const float value ){
	*(float*)endianBuf = little_float(value);
	Write(endianBuf, sizeof(value));
}
void				File::WriteDouble( const double value ){
	*(double*)endianBuf = little_double(value);
	Write(endianBuf, sizeof(value));
}
void				File::WriteBool( const bool value ){
	unsigned char b = value? 1: 0;
	Write(&b,sizeof(b));
}
void				File::WriteString( const char *string ){
	int length = inf::Str::length(string);
	if(length == -1) return;    // failed!

	WriteUnsignedShort((unsigned short)length);
	int realLen = Write(string, length);
	if( realLen == 0 )
		return; // failed!
	WriteChar('\0');
}
void				File::WriteVec2( const inf::Vec2 &vec ){
	WriteFloatArray(vec.to_float_ptr(), vec.get_dimension());
}
void				File::WriteVec3( const inf::Vec3 &vec ){
	WriteFloatArray(vec.to_float_ptr(), vec.get_dimension());
}
void				File::WriteCQuat( const inf::CQuat& quat )
{
	WriteFloatArray(quat.to_float_ptr(), quat.get_dimension());
}
void				File::WriteAngles( const inf::Angles& angles )
{
	WriteFloatArray(angles.to_float_ptr(), angles.get_dimension());
}

void				File::WriteVec4( const inf::Vec4 &vec ){
	WriteFloatArray(vec.to_float_ptr(), vec.get_dimension());
}
void				File::WriteMat3( const inf::Mat3 &mat ){
	WriteFloatArray(mat.to_float_ptr(), mat.get_dimension());
}
void				File::WriteFloatArray( const float* src, const int num )
{
	for(int i=0; i<num; ++i) {
		WriteFloat(src[i]);
	}
}


